/**
 * $Id: tracker.c 6 2009-05-06 15:20:27Z hannes@napoleon.bin-laden.biz $
 * Tracker functions
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
#include <mysql/mysql.h>

#include "tracker.h"
#include "cfg.h"
#include "bencode.h"
#include "buf.h"
#include "urldecode.h"

void tracker_handle_req(struct http_thread_vars *http_vars)
{
	struct tracker_thread_vars *tracker_vars[THREADS];
	tracker_vars[http_vars->tid] = malloc(sizeof(struct tracker_thread_vars));

	memset(tracker_vars[http_vars->tid]->params, 0, 32);	
	tracker_vars[http_vars->tid]->params[0] = strtok(http_vars->params[1], " ");
	for (tracker_vars[http_vars->tid]->i = 1; tracker_vars[http_vars->tid]->i < 20; tracker_vars[http_vars->tid]->i++) {
		tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i] = strtok(NULL, " ");
	}	
	
	/* Passkey */
	tracker_vars[http_vars->tid]->passkey = strtok(tracker_vars[http_vars->tid]->params[0]+1, "/");

	#ifdef DEBUG
		printf("tracker.c passkey %s\n", tracker_vars[http_vars->tid]->passkey);
	#endif	

	for (tracker_vars[http_vars->tid]->i = 1; tracker_vars[http_vars->tid]->i < 20; tracker_vars[http_vars->tid]->i++) {
        /* info_hash */
		if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i], "info_hash")) {
			tracker_vars[http_vars->tid]->info_hash = url_decode(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]);			
			#ifdef DEBUG
				printf("tracker.c info_hash %s\n", tracker_vars[http_vars->tid]->info_hash);
			#endif
        /* peer_id */
        } else if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i], "peer_id")) {
			tracker_vars[http_vars->tid]->peer_id = url_decode(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]);
			#ifdef DEBUG
				printf("tracker.c peer_id %s\n", tracker_vars[http_vars->tid]->peer_id);
        	#endif
		/**
		 * event
		 *
		 * -1 = error
         * 	0 = started
		 * 	1 = stopped
		 * 	2 = completed
		 */
		} else if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i], "event")) {
			if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1], "started")) {
				/* New Peer */
				tracker_vars[http_vars->tid]->event = 0;
			} else if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1], "stopped")) {
				/* Peer is no longer present. */
				tracker_vars[http_vars->tid]->event = 1;
			} else if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1], "completed")) {
				/* Peer has completed the download. */
				tracker_vars[http_vars->tid]->event = 2;
			} else {
				tracker_vars[http_vars->tid]->event = -1;
			}
			printf("tracker.c event %i\n", tracker_vars[http_vars->tid]->event);
        /* port-number */
        } else if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i], "port")) {
			if (atoi(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]) <= 65535) {
				tracker_vars[http_vars->tid]->portnum = atoi(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]);
			} else {
				tracker_vars[http_vars->tid]->portnum = 0;
			}
			#ifdef DEBUG
				printf("tracker.c port %i\n", tracker_vars[http_vars->tid]->portnum);
			#endif
        /* uploaded */
        } else if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i], "uploaded")) {
			if (atol(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]) <= LONG_MAX) {
				tracker_vars[http_vars->tid]->uploaded = 0;
				tracker_vars[http_vars->tid]->uploaded = atol(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]);
			} else {
				tracker_vars[http_vars->tid]->uploaded = 0;
			}
			#ifdef DEBUG
				printf("tracker.c uploaded %lu\n", tracker_vars[http_vars->tid]->uploaded);
			#endif
        /* downloaded */
        } else if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i], "downloaded")) {
            if (atol(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]) <= LONG_MAX) {
                tracker_vars[http_vars->tid]->downloaded = 0;
				tracker_vars[http_vars->tid]->downloaded = atol(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]);
            } else {
                tracker_vars[http_vars->tid]->downloaded = 0;
            }
			#ifdef DEBUG
				printf("tracker.c downloaded %lu\n", tracker_vars[http_vars->tid]->downloaded);
			#endif
        /* left */
		} else if (!strcmp(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i], "left")) {
			if (atol(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]) <= LONG_MAX) {
				tracker_vars[http_vars->tid]->left = 0;
				tracker_vars[http_vars->tid]->left = atol(tracker_vars[http_vars->tid]->params[tracker_vars[http_vars->tid]->i+1]);
			} else {
				tracker_vars[http_vars->tid]->left = 0;
			}
			#ifdef DEBUG
				printf("tracker.c left %lu\n", tracker_vars[http_vars->tid]->left);
			#endif
        }	
	}


	if (strlen(tracker_vars[http_vars->tid]->passkey) == 32 && strlen(tracker_vars[http_vars->tid]->info_hash) == 20 && strlen(tracker_vars[http_vars->tid]->peer_id) == 20) {
		tracker_run(tracker_vars[http_vars->tid], http_vars);
	} else {
		tracker_send_error(http_vars, "Access violation in 0x4e69676761682053746f6c65206d79206572726f72");
	} 

	free(tracker_vars[http_vars->tid]);
}

void tracker_send_error(struct http_thread_vars *http_vars, char *msg)
{
	struct buf *b;
	char header[128];
	char content[128];	

	b = buf_new();
	
	sprintf(header, "HTTP/1.1 200 OK\r\nConnection: close\r\nServer: %s\r\nContent-Type: text/plain\r\n\r\n", SERVER_VERSION);	
	buf_append_data(b, header, strlen(header));
	sprintf(content, "d14:failure reason%se\r\n", benc_str(msg));
	buf_append_data(b, content, strlen(content));	

	write(http_vars->sa, b->ptr, b->len);

}

void tracker_send_resp(struct http_thread_vars *http_vars, char *msg) 
{

	struct buf *b;
	char header[128];
	
	b = buf_new();

	sprintf(header, "HTTP/1.1 200 OK\r\nConnection: close\r\nServer: %s\r\nContent-Type: text/plain\r\n\r\n", SERVER_VERSION);
	buf_append_data(b, header, strlen(header));
	buf_append_data(b, msg, strlen(msg));
	
	write(http_vars->sa, b->ptr, b->len);
}

void tracker_run(struct tracker_thread_vars *tracker_vars, struct http_thread_vars *http_vars)
{
	MYSQL mysql[THREADS];
	MYSQL_ROW row[THREADS];
	MYSQL_RES *res[THREADS];
	struct buf *b[THREADS];
	mysql_init(&mysql[http_vars->tid]);
	
	if (mysql_real_connect(&mysql[http_vars->tid], MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB, 0, NULL, 0)) {
		
		/* Escape the passkey to prevent SQL-Injection */
		mysql_real_escape_string(&mysql[http_vars->tid], tracker_vars->escaped_passkey, tracker_vars->passkey, strlen(tracker_vars->passkey));
		memset(tracker_vars->query, 0, 512);
	
		#ifdef DEBUG
			printf("tracker.c escaped-passkey %s\n", tracker_vars->escaped_passkey);
		#endif	

		sprintf(tracker_vars->query, "SELECT id FROM users WHERE passkey = '%s' LIMIT 1", tracker_vars->escaped_passkey);
		mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
		res[http_vars->tid] = mysql_store_result(&mysql[http_vars->tid]);
		
		tracker_vars->num_rows = 0;
		tracker_vars->num_rows = mysql_num_rows(res[http_vars->tid]);

		#ifdef DEBUG
			printf("tracker.c passkey_rows %i\n", tracker_vars->num_rows);
		#endif
			
		if (tracker_vars->num_rows == 1) {	
	
			row[http_vars->tid] = mysql_fetch_row(res[http_vars->tid]);
			tracker_vars->userid = atoi(row[http_vars->tid][0]); 

			#ifdef DEBUG
				printf("tracker.c userID %i\n", tracker_vars->userid);
			#endif

			mysql_real_escape_string(&mysql[http_vars->tid], tracker_vars->escaped_info_hash, tracker_vars->info_hash, strlen(tracker_vars->info_hash));
			mysql_real_escape_string(&mysql[http_vars->tid], tracker_vars->escaped_peer_id, tracker_vars->peer_id, strlen(tracker_vars->peer_id));	
			memset(tracker_vars->query, 0, 512);	
		
			sprintf(tracker_vars->query, "SELECT id FROM torrents WHERE info_hash = '%s' LIMIT 1", tracker_vars->escaped_info_hash);
			mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
			res[http_vars->tid] = mysql_store_result(&mysql[http_vars->tid]);
		
			tracker_vars->num_rows = 0;
			tracker_vars->num_rows = mysql_num_rows(res[http_vars->tid]);

			#ifdef DEBUG
				printf("tracker.c torrent_rows %i\n", tracker_vars->num_rows);
			#endif
	
			if (tracker_vars->num_rows == 1) {
				row[http_vars->tid] = mysql_fetch_row(res[http_vars->tid]);
				tracker_vars->torrentid = atoi(row[http_vars->tid][0]);

				#ifdef DEBUG
					printf("tracker.c torrentID %i\n", tracker_vars->torrentid);
				#endif
		
				if (tracker_vars->event == 0) {
					/* We have a new peer. */
					
					#ifdef DEBUG
						printf("tracker.c event started\n");
					#endif

					if (tracker_vars->left == 0) {
						/* We have a seeder. */

						#ifdef DEBUG
							printf("tracker.c state seeder\n");
						#endif

                        memset(tracker_vars->query, 0, 512);
                        sprintf(tracker_vars->query, "INSERT INTO peers (torrent, peer_id, ip, port, to_go, started, last_action, userid, seeder) VALUES(%i, '%s', '%s', %i, %lu, NOW(), NOW(), %i, 'yes')", tracker_vars->torrentid, tracker_vars->escaped_peer_id, http_vars->ip, tracker_vars->portnum, tracker_vars->left, tracker_vars->userid);
						mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

						#ifdef DEBUG
							printf("tracker.c insert_query %s\n", tracker_vars->query);
						#endif

						/* Update the users stats. */
						memset(tracker_vars->query, 0, 512);
						sprintf(tracker_vars->query, "UPDATE users SET downloaded = downloaded + %lu, uploaded = uploaded + %lu WHERE id=%i", tracker_vars->downloaded, tracker_vars->uploaded, tracker_vars->userid);
						mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

						#ifdef DEBUG
							printf("tracker.c update_query %s\n", tracker_vars->query);
						#endif

						/* Update the peers table. */
						memset(tracker_vars->query, 0, 512);
						sprintf(tracker_vars->query, "UPDATE peers SET downloaded = %lu, uploaded = %lu, to_go = %lu, seeder = 'yes', last_action = NOW() WHERE userid = %i AND torrent = %i", tracker_vars->downloaded, tracker_vars->uploaded, tracker_vars->left, tracker_vars->userid, tracker_vars->torrentid);
						mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

						#ifdef DEBUG
							printf("tracker.c update_query %s\n", tracker_vars->query);
						#endif
						
						b[http_vars->tid] = buf_new();
						
						
                        memset(tracker_vars->buf, 0, 256);
                        sprintf(tracker_vars->buf, "d%si%ie%sl", benc_str("interval"), ANNOUNCE_INTERVAL, benc_str("peers"));
                        buf_append_data(b[http_vars->tid], tracker_vars->buf, strlen(tracker_vars->buf));

                        memset(tracker_vars->query, 0, 512);
                        sprintf(tracker_vars->query, "SELECT peer_id, ip, port FROM peers WHERE torrent = %i AND seeder = 'no' ORDER BY RAND() LIMIT 200", tracker_vars->torrentid);

						#ifdef DEBUG
							printf("tracker.c select_query %s\n", tracker_vars->query);
						#endif

                        mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
						res[http_vars->tid] = mysql_store_result(&mysql[http_vars->tid]);

						while ((row[http_vars->tid] = mysql_fetch_row(res[http_vars->tid]))) {
							memset(tracker_vars->buf, 0, 256);
							sprintf(tracker_vars->buf, "d7:peer id%s2:ip%s4:porti%iee", benc_str(row[http_vars->tid][0]), benc_str(row[http_vars->tid][1]), atoi(row[http_vars->tid][2]));
							buf_append_data(b[http_vars->tid], tracker_vars->buf, strlen(tracker_vars->buf));
						}
					

						buf_append_data(b[http_vars->tid], "ee\r\n", 4);

						#ifdef DEBUG
							printf("tracker.c resp %s\n", b[http_vars->tid]->ptr);
						#endif
						
						tracker_send_resp(http_vars, b[http_vars->tid]->ptr);						

						buf_free(b[http_vars->tid]);
					} else if (tracker_vars->left > 0) { 
						/* We have a leecher. */
						#ifdef DEBUG
							printf("tracker.c state leecher\n");
						#endif

						memset(tracker_vars->query, 0, 512);
                        sprintf(tracker_vars->query, "INSERT INTO peers (torrent, peer_id, ip, port, to_go, started, last_action, userid, seeder) VALUES(%i, '%s', '%s', %i, %lu, NOW(), NOW(), %i, 'no')", tracker_vars->torrentid, tracker_vars->escaped_peer_id, http_vars->ip, tracker_vars->portnum, tracker_vars->left, tracker_vars->userid);
                        mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

						#ifdef DEBUG
							printf("tracker.c insert_query %s\n", tracker_vars->query);
						#endif

						b[http_vars->tid] = buf_new();

						memset(tracker_vars->buf, 0, 256);
						sprintf(tracker_vars->buf, "d%si%ie%sl", benc_str("interval"), ANNOUNCE_INTERVAL, benc_str("peers"));
						buf_append_data(b[http_vars->tid], tracker_vars->buf, strlen(tracker_vars->buf));

						memset(tracker_vars->query, 0, 512);
						sprintf(tracker_vars->query, "SELECT peer_id, ip, port FROM peers WHERE torrent = %i ORDER BY RAND() LIMIT 200", tracker_vars->torrentid);

						#ifdef DEBUG
                            printf("tracker.c select_query %s\n", tracker_vars->query);
                        #endif

						mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
						res[http_vars->tid] = mysql_store_result(&mysql[http_vars->tid]);
						tracker_vars->num_rows = 0;
						tracker_vars->num_rows = mysql_num_rows(res[http_vars->tid]);	

						while ((row[http_vars->tid] = mysql_fetch_row(res[http_vars->tid]))) {
							#ifdef DEBUG
								printf("tracker.c peer_ip %s\n", row[http_vars->tid][1]);
							#endif

							memset(tracker_vars->buf, 0, 256);
							sprintf(tracker_vars->buf, "d7:peer id%s2:ip%s4:porti%iee", benc_str(row[http_vars->tid][0]), benc_str(row[http_vars->tid][1]), atoi(row[http_vars->tid][2]));
							buf_append_data(b[http_vars->tid], tracker_vars->buf, strlen(tracker_vars->buf));
						}
						buf_append_data(b[http_vars->tid], "ee\r\n", 4);
						#ifdef DEBUG
							printf("tracker.c resp %s\n", b[http_vars->tid]->ptr);
						#endif

						tracker_send_resp(http_vars, b[http_vars->tid]->ptr);
						buf_free(b[http_vars->tid]);
					}
				} else if (tracker_vars->event == 1) {
					/* Peer is no longer active in swarm. */
					#ifdef DEBUG
						printf("tracker.c event stopped\n");
					#endif

					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "DELETE FROM peers WHERE userid = %i AND torrent = %i", tracker_vars->userid, tracker_vars->torrentid);
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

					#ifdef DEBUG
						printf("tracker.c delete_query %s\n", tracker_vars->query);
					#endif
			
					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "UPDATE users SET downloaded = downloaded + %lu, uploaded = uploaded + %lu WHERE id = %i", tracker_vars->downloaded, tracker_vars->uploaded, tracker_vars->userid);
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
			
					#ifdef DEBUG
						printf("tracker.c update_query %s\n", tracker_vars->query);
					#endif

					memset(tracker_vars->buf, 0, 256);
					sprintf(tracker_vars->buf, "d8:intervali%ie5:peerslee\r\n", ANNOUNCE_INTERVAL);
					
					#ifdef DEBUG
						printf("tracker.c resp %s\n", tracker_vars->buf);
					#endif

					tracker_send_resp(http_vars, tracker_vars->buf);
				} else if (tracker_vars->event == 2) {
					/* Peer has completed the download and is now seeding. */
					#ifdef DEBUG
						printf("tracker.c event completed");
					#endif
					
					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "SELECT id FROM peers WHERE userid = %i AND torrent = %i LIMIT 1");
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
					res[http_vars->tid] = mysql_store_result(&mysql[http_vars->tid]);

					#ifdef DEBUG
						printf("tracker.c select_query %s\n", tracker_vars->query);
					#endif

					tracker_vars->num_rows = 0;
					tracker_vars->num_rows = mysql_num_rows(res[http_vars->tid]);

					/**
					 * Insert Peer into peers if he's new in the swarm. 
					 * This usally won't happen, but to be on the safe side I'm checking.
					 */
					if (tracker_vars->num_rows == 0) {
						memset(tracker_vars->query, 0, 512);
						sprintf(tracker_vars->query, "INSERT INTO peers (torrent, peer_id, ip, port, to_go, started, last_action, userid, seeder) VALUES(%i, '%s', '%s', %i, %lu, NOW(),     NOW(), %i, 'yes')", tracker_vars->torrentid, tracker_vars->escaped_peer_id, http_vars->ip, tracker_vars->portnum, tracker_vars->left, tracker_vars->userid);
						mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));	
					
						#ifdef DEBUG
							printf("tracker.c insert_query %s\n", tracker_vars->query);
						#endif
					}

					/* Update the users stats. */
					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "UPDATE users SET downloaded = downloaded + %lu, uploaded = uploaded + %lu WHERE id=%i", tracker_vars->downloaded, tracker_vars->uploaded, tracker_vars->userid);
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

					#ifdef DEBUG
						printf("tracker.c update_query %s\n", tracker_vars->query);
					#endif

					/* Update the peers table. */
					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "UPDATE peers SET downloaded = %lu, uploaded = %lu, to_go = %lu, seeder = 'yes', last_action = NOW(), finishedat = UNIX_TIMESTAMP() WHERE userid = %i AND torrent = %i", tracker_vars->downloaded, tracker_vars->uploaded, tracker_vars->left, tracker_vars->userid, tracker_vars->torrentid);
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

					#ifdef DEBUG
						printf("tracker.c update_query %s\n", tracker_vars->query);
					#endif
					
					b[http_vars->tid] = buf_new();
					
					/* Begin building the response. */
					memset(tracker_vars->buf, 0, 256);
					sprintf(tracker_vars->buf, "d%si%ie%sl", benc_str("interval"), ANNOUNCE_INTERVAL, benc_str("peers"));
					buf_append_data(b[http_vars->tid], tracker_vars->buf, strlen(tracker_vars->buf));

					/* Fetch the peers form the database. */
					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "SELECT peer_id, ip, port FROM peers WHERE torrent = %i AND seeder = 'no' ORDER BY RAND() LIMIT 200", tracker_vars->torrentid);	
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
					res[http_vars->tid] = mysql_store_result(&mysql[http_vars->tid]);
					
					#ifdef DEBUG
						printf("tracker.c select_query %s\n", tracker_vars->query);
					#endif

					/* Looping through the result set and continue bilding the response. */
					while ((row[http_vars->tid] = mysql_fetch_row(res[http_vars->tid]))) {
						memset(tracker_vars->buf, 0, 256);
						sprintf(tracker_vars->buf, "d7:peer id%s2:ip%s4:porti%iee", benc_str(row[http_vars->tid][0]), benc_str(row[http_vars->tid][1]), atoi(row[http_vars->tid][2]));		
						buf_append_data(b[http_vars->tid], tracker_vars->buf, strlen(tracker_vars->buf));
					}					
					buf_append_data(b[http_vars->tid], "ee\r\n", 4);						

					#ifdef DEBUG
						printf("tracker.c resp %s\n", b[http_vars->tid]->ptr);
					#endif

					tracker_send_resp(http_vars, b[http_vars->tid]->ptr);

					buf_free(b[http_vars->tid]);	
				} else {
					#ifdef DEBUG
						printf("tracker.c event regular");
					#endif			
					
					/* Check if the torrent exists in the database. */
					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "SELECT id FROM peers WHERE userid = %i AND torrent = %i LIMIT 1", tracker_vars->userid, tracker_vars->torrentid);
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
					res[http_vars->tid] = mysql_store_result(&mysql[http_vars->tid]);

					#ifdef DEBUG
						printf("tracker.c select_query %s\n");
					#endif					
					
					tracker_vars->num_rows = 0;
					tracker_vars->num_rows = mysql_num_rows(res[http_vars->tid]);
					
					if (tracker_vars->num_rows = 0) {
						memset(tracker_vars->query, 0, 512);
						if (tracker_vars->left = 0) {
							/* Seeder */
							sprintf(tracker_vars->query, "INSERT INTO peers (torrent, peer_id, ip, port, to_go, started, last_action, userid, seeder) VALUES(%i, '%s', '%s', %i, %lu, NOW(), NOW(), %i, 'yes')", tracker_vars->torrentid, tracker_vars->escaped_peer_id, http_vars->ip, tracker_vars->portnum, tracker_vars->left, tracker_vars->userid);
						} else {
							/* Leecher */
							sprintf(tracker_vars->query, "INSERT INTO peers (torrent, peer_id, ip, port, to_go, started, last_action, userid, seeder) VALUES(%i, '%s', '%s', %i, %lu, NOW(), NOW(), %i, 'no')", tracker_vars->torrentid, tracker_vars->escaped_peer_id, http_vars->ip, tracker_vars->portnum, tracker_vars->left, tracker_vars->userid);
						}
						mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
						
						#ifdef DEBUG
							printf("tracker.c insert_query %s\n", tracker_vars->query);
						#endif
		
					}

					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "UPDATE users SET downloaded = downloaded + %lu, uploaded = uploaded + %lu WHERE id = %i", tracker_vars->downloaded, tracker_vars->uploaded, tracker_vars->userid);
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

					#ifdef DEBUG
						printf("tracker.c update_query %s\n", tracker_vars->query);
					#endif

					memset(tracker_vars->query, 0, 512);
					sprintf(tracker_vars->query, "UPDATE peers SET downloaded = %lu, uploaded = %lu, to_go = %lu, last_action = NOW() WHERE userid = %i AND torrent = %i", tracker_vars->downloaded, tracker_vars->uploaded, tracker_vars->left, tracker_vars->userid, tracker_vars->torrentid);
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));

					#ifdef DEBUG
						printf("tracker.c upate_query %s\n", tracker_vars->query);
					#endif

					b[http_vars->tid] = buf_new();

					/* Begin building the response. */
					memset(tracker_vars->buf, 0, 256);
					sprintf(tracker_vars->buf, "d%si%ie%sl", benc_str("interval"), ANNOUNCE_INTERVAL, benc_str("peers"));
					buf_append_data(b[http_vars->tid], tracker_vars->buf, strlen(tracker_vars->buf));

					/* Fetch the peers form the database. */
					memset(tracker_vars->query, 0, 512);
					
					if (tracker_vars->left == 0) {
						sprintf(tracker_vars->query, "SELECT peer_id, ip, port FROM peers WHERE torrent = %i AND seeder = 'no' ORDER BY RAND() LIMIT 200", tracker_vars->torrentid);
					} else {
						sprintf(tracker_vars->query, "SELECT peer_id, ip, port FROM peers WHERE torrent = %i ORDER BY RAND() LIMIT 200", tracker_vars->torrentid);
					}
					mysql_real_query(&mysql[http_vars->tid], tracker_vars->query, strlen(tracker_vars->query));
					res[http_vars->tid] = mysql_store_result(&mysql[http_vars->tid]);

					#ifdef DEBUG
						printf("tracker.c select_query %s\n", tracker_vars->query);
					#endif

					/* Looping through the result set and continue bilding the response. */
					while ((row[http_vars->tid] = mysql_fetch_row(res[http_vars->tid]))) {
						memset(tracker_vars->buf, 0, 256);
						sprintf(tracker_vars->buf, "d7:peer id%s2:ip%s4:porti%iee", benc_str(row[http_vars->tid][0]), benc_str(row[http_vars->tid][1]), atoi(row[http_vars->tid][2]));
						buf_append_data(b[http_vars->tid], tracker_vars->buf, strlen(tracker_vars->buf));
					}
					buf_append_data(b[http_vars->tid], "ee\r\n", 4);

					#ifdef DEBUG
						printf("tracker.c resp %s\n", b[http_vars->tid]->ptr);
					#endif

					tracker_send_resp(http_vars, b[http_vars->tid]->ptr);

					buf_free(b[http_vars->tid]);
				}
				/* Free up some vars allocated by the urldecode() function. */
				free(tracker_vars->peer_id);
				free(tracker_vars->info_hash);
			} else {
				tracker_send_error(http_vars, "Torrent not registered on tracker.");
			}
		} else {
			tracker_send_error(http_vars, "Passkey does not exist.");
		}	
	} else {
		tracker_send_error(http_vars, "MySQL Server is unreachable.");
	}
}
